package titt.io.encoding.array;

import java.io.ByteArrayOutputStream;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;

import titt.io.encoding.Decoder;
import titt.type.Type;
import titt.type.Types;
import titt.util.Bytes;

public class ArrayDecoder implements Decoder {

	private Decoder nonarray;
	private byte[] nullArray = Bytes.asBytes(Types.NULL_TOKEN);

	public ArrayDecoder(Decoder nonarray) {
		this.nonarray = nonarray;
	}

	@Override
	public Object decode(Type t, byte[] b) {		
		if(t.isArray()) {

			if(Arrays.equals(b, nullArray)) return null;		

			int depth = 0;
			Type sub = t.subtype();
			ByteArrayOutputStream buf = new ByteArrayOutputStream();

			boolean onemore = false;

			ArrayList<byte[]> holder = new ArrayList<byte[]>();

			for(int i = 1; i < b.length - 1; i++) {
				byte c = b[i];

				if(c == Types.ARRAY_START)	depth++;
				if(c == Types.ARRAY_END) 	depth--;

				if(depth == 0 && c == Types.ARRAY_SPLITTER) {
					byte[] element = buf.toByteArray();
					if(element.length > 0)
						holder.add(element);

					buf.reset();
					onemore = false;
				}
				else {
					onemore = true;
					buf.write(c);
				}
			}
			if(onemore) {
				byte[] element = buf.toByteArray();
				if(element.length > 0)
					holder.add(element);
			}

			Object arr = Array.newInstance(sub.asClass(), holder.size());
			for(int i = 0; i < holder.size(); i++)
				Array.set(arr, i, decode(sub, holder.get(i)));

			return arr;
		}		

		return nonarray.decode(t, b);
	}

	@Override
	public boolean isDecodeable(Type t) {
		return (t.isArray() && isDecodeable(t.subtype())) || nonarray.isDecodeable(t);
	}

}